/**
 * @author 徐楠
 * @date 2022/2/24 22:37
 * @version 1.0
 */

package com.xunan.likou;

public class StringToIntegerConversion {
    public static void main(String[] args) {
        String s = "   ";
        int result = myAtoi2(s);
        System.out.println(result);
        //System.out.println(new Integer((int) Math.pow(2,31)));
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MAX_VALUE / 10);
        System.out.println(Integer.MAX_VALUE % 10);
        System.out.println('c' - '0');
        System.out.println('9' - '0');
    }

    /**
     * 由于题目要求结果必须在 32 位有符号整数范围内，
     * 因此在计算过程中需要判断整数的值是否超出范围。一种做法是用 long 型存储整数，
     * 另一种做法是在更新整数值之前判断更新后的整数值是否会超出范围。具体做法是，
     * 令 MAX = 2^31/10
     * <p>
     * 如果当前整数的值已经超过 MAX，则在更新整数的值之后一定超出范围；
     * <p>
     * 如果当前整数的值等于 MAX，则判断新的数字字符是否会导致更新整数后的值超出范围，
     * 如果在正数的情况下新的数字字符大于 77 或者在负数的情况下新的数字字符大于 88，
     * 则会超出范围，因为 2^{31} - 1 = 21474836472，-2^{31} = -2147483648
     * <p>
     * 如果遇到整数的值超出范围，则在正数的情况下返回 2^{31} - 1，在负数的情况下返回 -2^{31}。
     * <p>
     * 如果计算结束时，整数的值没有超出范围，则根据整数的正负性得到最终结果并返回。
     *
     * @param s
     * @return
     */
    public static int myAtoi1(String s) {
        int length = s.length();
        int index = 0;
        while (index < length && s.charAt(index) == ' ') {
            index++;
        }
        if (index == length) {
            return 0;
        }
        int sign = 1;
        if (s.charAt(index) == '+') {
            index++;
        } else if (s.charAt(index) == '-') {
            sign = -1;
            index++;
        }
        final int MAX = Integer.MAX_VALUE / 10;
        int num = 0;
        while (index < length && Character.isDigit(s.charAt(index))) {
            int digit = s.charAt(index) - '0';
            if (num > MAX) {
                return sign > 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            } else if (num == MAX) {
                if (sign > 0 && digit > 7) {
                    return Integer.MAX_VALUE;
                } else if (sign < 0 && digit > 8) {
                    return Integer.MIN_VALUE;
                }
            }
            num = num * 10 + digit;
            index++;
        }
        return num * sign;
    }

    public static int myAtoi2(String s) {
        int len = s.length();
        // s.charAt(i) 方法回去检查下标的合法性，一般先转换成字符数组
        char[] charArray = s.toCharArray();

        // 1、去除前导空格
        int index = 0;
        while (index < len && charArray[index] == ' ') {
            index++;
        }

        // 2、如果已经遍历完成（针对极端用例 "      "）
        if (index == len) {
            return 0;
        }

        // 3、如果出现符号字符，仅第 1 个有效，并记录正负
        int sign = 1;
        char firstChar = charArray[index];
        if (firstChar == '+') {
            index++;
        } else if (firstChar == '-') {
            index++;
            sign = -1;
        }

        // 4、将后续出现的数字字符进行转换
        // 不能使用 long 类型，这是题目说的
        int res = 0;
        //MAX = 2^31/10
        while (index < len) {
            char currChar = charArray[index];
            // 4.1 先判断不合法的情况
            if (currChar > '9' || currChar < '0') {
                break;
            }

            // 题目中说：环境只能存储 32 位大小的有符号整数，因此，需要提前判：断乘以 10 以后是否越界
            if (res > Integer.MAX_VALUE / 10 ||
                    (res == Integer.MAX_VALUE / 10 &&
                            (currChar - '0') > Integer.MAX_VALUE % 10)) {
                return Integer.MAX_VALUE;
            }
            if (res < Integer.MIN_VALUE / 10 ||
                    (res == Integer.MIN_VALUE / 10 &&
                            (currChar - '0') > -(Integer.MIN_VALUE % 10))) {
                return Integer.MIN_VALUE;
            }

            // 4.2 合法的情况下，才考虑转换，每一步都把符号位乘进去
            res = res * 10 + sign * (currChar - '0');
            index++;
        }
        return res;
    }

}
